﻿/**
 * Licensed to Open-Ones Group under one or more contributor license
 * agreements. See the NOTICE file distributed with this work
 * for additional information regarding copyright ownership.
 * Open-Ones Group licenses this file to you under the Apache License,
 * Version 2.0 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a
 * copy of the License at:
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
namespace IPresenter
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Net;
    using System.Net.Sockets;
    using System.Text;
    using System.Threading;
    using System.Windows.Forms;
    using InTheHand.Net.Bluetooth;
    using InTheHand.Net.Sockets;

    /// <summary>
    /// Class is used to execute related process to Server
    /// </summary>
    public class ServerIPresenter
    {
        /// <summary>
        /// Stream reader that is used to read message
        /// </summary>
        private StreamReader srReader;

        /// <summary>
        /// socket server
        /// </summary>
        private Socket skServer;

        /// <summary>
        /// Socket accept
        /// </summary>
        private Socket skAccept;

        /// <summary>
        /// Bluetooth listener
        /// </summary>
        private BluetoothClient bltAccept;

        /// <summary>
        /// Stream writer that is used to receive message
        /// </summary>
        private StreamWriter swWriter;

        /// <summary>
        /// Bluetooth server
        /// </summary>
        private BluetoothListener bltServer;

        /// <summary>
        /// Variable update type's name connection
        /// </summary>
        private UpdateTypeConnection UpdateKindConnection;

        /// <summary>
        /// Update Name of Type Connection
        /// </summary>
        /// <param name="nameConnection">Name Connection</param>
        public delegate void UpdateTypeConnection(string nameConnection);

        /// <summary>
        /// Gets or sets StreamReader
        /// </summary>
        public StreamReader ReaderAdapter
        {
            get { return this.srReader; }
            set { this.srReader = value; }
        }

        /// <summary>
        /// Gets or sets StreamWriter
        /// </summary>
        public StreamWriter WriterAdapter
        {
            get { return this.swWriter; }
            set { this.swWriter = value; }
        }

        /// <summary>
        /// Gets or sets bluetooth server
        /// </summary>
        public BluetoothListener BltServer
        {
            get { return this.bltServer; }
            set { this.bltServer = value; }
        }

        /// <summary>
        /// Gets or sets Bluetooth Accept
        /// </summary>
        public BluetoothClient BltAccept
        {
            get { return this.bltAccept; }
            set { this.bltAccept = value; }
        }

        /// <summary>
        /// Gets or sets Socket accpet
        /// </summary>
        public Socket SocketAccept
        {
            get { return this.skAccept; }
            set { this.skAccept = value; }
        }

        /// <summary>
        /// Gets or sets Socket server
        /// </summary>
        public Socket SocketServer
        {
            get { return this.skServer; }
            set { this.skServer = value; }
        }

        /// <summary>
        /// Gets or sets updatekindconnection
        /// </summary>
        public UpdateTypeConnection UpdateConnection
        {
            get { return this.UpdateKindConnection; }
            set { this.UpdateKindConnection = value; }
        }

        /// <summary>
        /// Init server
        /// </summary>
        public void Init()
        {
            try
            {
                int intPort = 3333;
                this.skServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                this.skServer.Bind(new IPEndPoint(IPAddress.Any, intPort));
                this.skServer.Listen((int)SocketOptionName.MaxConnections);
                Threads.Start(this, Threads.SERVER_NETWORK);
            }
            catch (Exception ex)
            {
                Logs.WriteErrorMessage(ex.Message);
            }

            try
            {
                Guid gidServiceServer = new Guid("{7A51FDC2-FDDF-4c9b-AFFC-98BCD91BF93B}");
                BluetoothRadio bltRadioMode = BluetoothRadio.PrimaryRadio;
                bltRadioMode.Mode = RadioMode.Discoverable;
                this.bltServer = new BluetoothListener(gidServiceServer);
                this.bltServer.Start();
                Threads.Start(this, Threads.SERVER_BLUETOOTH);
            }
            catch (Exception ex)
            {
                Logs.WriteErrorMessage(ex.Message);
            }
        }

        /// <summary>
        /// Accept connection from Client via bluetooth
        /// </summary>
        public void AcceptBlueTooth()
        {
            try
            {
                this.bltAccept = this.bltServer.AcceptBluetoothClient();
                this.bltServer.Stop();
            }
            catch (Exception ex)
            {
                Logs.WriteErrorMessage(ex.Message);
            }

            try
            {
                Threads.ServerNetwork.Abort();
                this.skServer.Close();
            }
            catch (Exception ex)
            {
                Logs.WriteErrorMessage(ex.Message);
            }

            try
            {
                this.UpdateConnection("Connecting via bluetooth");
                while (this.bltAccept.Connected)
                {
                    this.srReader = new StreamReader(this.bltAccept.GetStream());
                    this.swWriter = new StreamWriter(this.bltAccept.GetStream());
                    string strMessage;
                    if (OptionIPresenter.Mode == OptionIPresenter.MODE_DEFAULT)
                    {
                        strMessage = BluetoothSupport.Read(this.bltAccept, this.srReader);
                        ExecuteCommand(strMessage);
                    }
                    else
                    {
                        if (OptionIPresenter.Mode == OptionIPresenter.MODE_EXTEND)
                        {
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Logs.WriteErrorMessage(ex.Message);
                this.bltAccept.Close();
            }
        }

        /// <summary>
        /// Accept connection from Client via wifi
        /// </summary>
        public void AcceptNetwork()
        {
            try
            {
                this.skAccept = this.skServer.Accept();
                this.skServer.Close();
            }
            catch (Exception ex)
            {
                Logs.WriteErrorMessage(ex.Message);
            }

            try
            {
                Threads.ServerBluetooth.Abort();
                this.bltServer.Stop();
            }
            catch (Exception ex)
            {
                Logs.WriteErrorMessage(ex.Message);
            }

            try
            {
                this.UpdateConnection("Connecting via wireless");
                while (this.skAccept.Connected)
                {
                    string strLength;
                    if (OptionIPresenter.Mode == OptionIPresenter.MODE_EXTEND)
                    {
                        List<string> lstMessage;
                        NetworkSupport.ReceiveMessageUnicode(this.skAccept, out strLength);
                        NetworkSupport.ReceiveMessageUnicode(this.skAccept, out lstMessage, int.Parse(strLength));
                        ExecuteCommand(lstMessage);
                    }
                    else
                    {
                        if (OptionIPresenter.Mode == OptionIPresenter.MODE_DEFAULT)
                        {
                            NetworkSupport.ReceiveMessageAscii(this.skAccept, out strLength, NetworkSupport.MAX_SIZE_OF_MESSAGE_LENGTH);
                            string strMessage;
                            try
                            {
                                bool t = NetworkSupport.ReceiveMessageAscii(this.skAccept, out strMessage, int.Parse(strLength));
                                if (t == false)
                                {
                                    Logs.WriteErrorMessage("Receive Message Fail");
                                }

                                ExecuteCommand(strMessage);
                            }
                            catch (Exception ex)
                            {
                                Logs.WriteErrorMessage(ex.Message);
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Logs.WriteErrorMessage(ex.Message);
                this.skAccept.Close();
            }
        }

        /// <summary>
        /// Abort connection to Client
        /// </summary>
        public void Dispose()
        {
            Threads.Dispose();
            try
            {
                this.skServer.Close();
                this.skAccept.Close();
            }
            catch (Exception ex)
            {
                Logs.WriteErrorMessage(ex.Message);
            }

            try
            {
                 this.bltServer.Stop();
                 this.bltAccept.Close();
            }
            catch (Exception ex)
            {
                Logs.WriteErrorMessage(ex.Message);
            }
        }

        /// <summary>
        /// Execute command from client
        /// </summary>
        /// <param name="command">Name of command</param>
        private static void ExecuteCommand(string command)
        {
            if (CommonCommand.IsContain(command))
            {
                CommonCommand.ExecuteCommand(command);
            }
            else
            {
                try
                {
                    int intSlideNumber = int.Parse(command);
                    PowerPointSupport.SlideNumber = intSlideNumber;
                    OpenOfficeSupport.SlideNumber = intSlideNumber;
                    CommonCommand.ExecuteCommand(PresentCommand.GO_TO_SLIDE);
                }
                catch (Exception ex)
                {
                    Logs.WriteErrorMessage(ex.Message);
                }
            }
        }

        /// <summary>
        /// Execute list of command from client
        /// </summary>
        /// <param name="commands">List of commands</param>
        private static void ExecuteCommand(List<string> commands)
        {
            commands = NetworkSupport.AnalysisMessage(commands);
            if (commands.Count == 1)
            {
                if (CommonCommand.IsContain(commands[0]))
                {
                    CommonCommand.ExecuteCommand(commands[0]);
                }
                else
                {
                    PowerPointSupport.DetermineWindowOrPresentation(commands[0]);
                    OpenOfficeSupport.DeterminePresentation(commands[0]);
                }
            }
        }
    }
}
